home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Deutsche Edition 1
/
Deutsche Edition 1.iso
/
amok
/
051-060
/
amok58
/
realconversions2
/
realconversions2.dok
< prev
next >
Wrap
Text File
|
1993-11-04
|
7KB
|
174 lines
DEFINITION RealConversions2;
*********************************************************************
ACHTUNG: Dieses Modul funktioniert auch mit LONGREAL-Zahlen! Es wird
dabei die bedingte Compilation ausgenutzt. Wird das Modul
normal compiliert, ist Real=REAL. Wird aber bei der
Compilation im CLI die Variable LONGREAL gesetzt, so ist
Real=LONGREAL.
Aufruf in CLI, um die LONGREAL-Version zu erzeugen:
Oberon SET LONGREAL RealConversions2
Es werden dann die Dateien LongRealConversion2.sym und
LongRealConversions2.obj erzeugt.
*********************************************************************
PROCEDURE DeleteSpaces(VAR str:ARRAY OF CHAR);
PROCEDURE StringToReal(str:ARRAY OF CHAR;
VAR x:Real):BOOLEAN;
PROCEDURE RealToString(x:Real;
VAR str:ARRAY OF CHAR;
gs,nks:INTEGER;expo,left:BOOLEAN):BOOLEAN;
Die Prozedur StringToReal() wandelt eine als String vorliegende Zahl
in eine (rechnerinterne) REAL- bzw. LONGREAL-Zahl um. RealToString()
wandelt umgekehrt eine reelle Zahl von der rechnerinternen Darstellung
in eine lesbare Zeichenkette um.
Was ist nun der Vorteil von RealConversions2 gegenüber dem Modul
RealConversions, welches zum Amiga-Oberon-Compiler V2.0 mitgeliefert
wurde?
Zuerst einmal ist das originale RealConversions bei der Umwandlung
recht ungenau: Wandelt man eine n-stellige REAL-Zahl, welche als
Zeichenkette vorliegt, in die rechnerinterne Darstellung und dann
wieder zurückt in eine Zeichenkette, so bekommt man auch bei n<7 nicht
immer die ursprüngliche Ziffernfolge. Außerdem gefällt mir das
Zahlenformat, welches die originale Prozedur RealToString() liefert
nicht übermäßig.
Nun zu der Beschreibung der beiden Prozeduren:
PROCEDURE StringToReal(str:ARRAY OF CHAR; VAR x:Real):BOOLEAN;
Die Zeichenkette str wird in die reelle Zahl x umgewandelt. Das
Resultat ist TRUE, wenn die Zeichenkette folgender Gramatik
entspricht:
digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9".
sign = ["+"|"-"].
int = {digit}.
real = sign int ["." int] [("E"|"e") sign int]
Die Zeichenkette darf KEINE Leerzeichen enthalten.
Falls man Zeichenketten mit Leerzeichen verarbeiten will, kann man
zuvor mit der Prozedur DeleteSpaces() die Leerzeichen entfernen.
Falls die Zahl den REAL- bzw. LONGREAL-Bereich überschreitet, wird
FALSE zurückgegeben.
Beispiele:
Zeichenkette Zahl Resultat
"" 0.0 TRUE
"1" 1.0 TRUE
"3.84" 3.84 TRUE
"-.34532" -0.34532 TRUE
"23." 23.0 TRUE
".E" 0.0 TRUE
"-34.5E+12" -3.45E13 TRUE
"3,4" --- FALSE
"--3" --- FALSE
"3.45.E3" --- FALSE
"9.8E372" --- FALSE
PROCEDURE RealToString(x:Real;
VAR str:ARRAY OF CHAR;
gs,nks:INTEGER;expo,left:BOOLEAN):BOOLEAN;
RealToString() wandelt die Zahl x in einen String um. Dabei gibt gs
an, mit wie viel signifikanten Ziffern die Zahl dargestellt werden
soll. Folgende Zahlen haben je 5 signifikante Ziffern:
12345
123.45
1.2345E-13
0.000000054321
Die führenden Nullen bei der letzten Zahl sind keine signifikanten
Ziffern, da 0.000000054321 = 5.4321E-8. Der Skalierungsfaktor E-8 ist
nur durch das verwendete Maßsystem bedingt und hat mit der Genauigkeit
der Zahl nichts zu tun:
0.012 m =12E-3 m = 12 mm
Obige Längenangaben in Metern oder Millimetern sind also gleichwertig,
die Genauigkeit ist je zweistellig bzw. 1/100 = 1%
Manchmal möchte man die Zahl der Nachkommastellen beschränken,
beispielsweise will man bei Preisangabe in DM nicht mehr als 2
Nachkommastellen haben. Daher kann man mit nks die Zahl der
Nachkommastellen beschränken. Ist nks=n, so bekommt der String maximal
n Nachkommastellen. Hat x mehr Vorkommastellen als gs erlaubt, so wird
automatisch die wissenschaftliche Zahlendarstellung mit Exponent
verwendet. (xEnn entspricht dabei x * 10^nn.) Ist expo=TRUE, wird
diese wissenschaftliche Zahlendarstellung stets verwendet. Ist
left=TRUE, so wird die Zahl linksbündig in str eingetragen,
anderenfalls rechtsbündig. Die Zahl wird wie üblich gerundet, d.h.
wenn die Ziffer, welche der letzten sichtbaren Dezimalstelle folgen
würde, größer oder gleich fümf ist, wird aufgerundet.
123.456 ==> 123.46
-34.9973 ==> -35.00
Eine Besonderheit gibt es noch: Ist |x| < 1, so wird x mit weniger als
gs signifikanten Ziffern dargestellt. Der Grund ist, daß viele Leute
statt der vierstelligen Zahl 7.894E-11 lieber 0.000 lesen. Will man
dagegen die eigentlich korrekte Darstellung 7.894E-11 erhalten, so
muß der Prozeduraufruf folgendermaßen aussehen:
ok:=RealToString(zahl,str,4,4, ABS(x)<=1, left);
Ist |x|<=1, so wird automatisch die wissenschaftliche Darstellung
gewählt.
Das Resultat ist TRUE, wenn die Zahl in str Platz fand.
Zum Schluß noch etwas zur Genauigkeit:
Ich habe versucht, die Umwandlungsfehler, welche durch die endliche
Rechengenauigkeit entstehen, so gering wie möglich zu halten.
Insbesondere habe ich daher auf die Benutzung des Logarithmus und der
Exponentialfunktion verzichtet. Bei der Prozedur StringToReal() müssen
die einzelnen Zehnerpotenzen aufsummiert werden. Ich beginne die
Summation mit den kleinsten Potenzen. Dies ist zwar etwas
umständlicher, sollte aber eine größere nummerische Genauigkeit
ergeben. Selbstverständlich habe ich auch versucht, die Anzahl der
Rechenoperationen so gering wie möglich zu halten, da jede Operation
den nummerischen Fehler vergrößert.
Mit den beiliegenden Testprogrammen LRCTest (für LONGREAL) und RCTest
(für REAL), welche eine Zeichenkette einlesen, diese mit
StringToReal() in eine Real-Zahl und dann mit RealToString() wieder in
eine Zeichenkette umwandeln, kann man die Genauigkeit testen. Bei
REAL-Zahlen (eigentlich sind es FFP-Zahlen) wird fast eine
siebenstellige Genauigkeit erreicht. ( Nur fast, denn z.B 34 liefert
34.00001 ). Benutzt man LONGREAL-Zahlen, wird eine 14-stellige
Genauigkeit erreicht.
Alle Angaben selbstverständlich ohne Gewähr!
PS: Bei der Version 2.0 des Amiga-Oberon-Compilers führt das Rechnen mit
REAL-Konstanten manchmal zu recht großen nummerischen Ungenauigkeiten.
Beispielsweise ergibt die Multiplikation mit 1.0E-1 einen größeren
nummerischen Fehler als die Division durch 10. Ich habe daher
weitgehend auf die Benutzung von REAL-Konstanten verzichtet.
Stefan Salewski, 12.8.91